/*
 * ndmp_sysfs.c - The sysfs routine. This impliments the readonly attributes to read the NDMP session paramters
 * 
 *
 *      Author: Aboo Valappil
 *      Date: 2/10/2008
 *      Based on: None
 */

#include "ndmp_main.h"
#include "ndmp_ioctl.h"

/* do not impiment the sysfs function is the kernel version is less than 2.6.25. 
 * It is not that the earlier versiono do not support sysfs, but it is just too much of work.
 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)

int ndmp_create_kset(void)
{
	printk("ndmphba: ndmphba does not support sysfs objects in this kernel version, requires minimum 2.6.25\n");
        return 0;
}

void ndmp_destroy_session_kobj(struct ndmp_scsi_session *session)
{
	return;
}

int ndmp_create_session_kobj(struct ndmp_scsi_session *session)
{
        return 0;

}
void ndmp_scsi_kset_remove(void)
{
	return;
}


/* The following are to impliment sysfs objects and attribute functionality. */
#else

extern struct ndmp_scsi_sessions sessions;

#define to_ndmp_session(x) container_of(x, struct ndmp_scsi_session, ko)	

struct ndmp_session_attribute {
        struct attribute attr;
        ssize_t (*show)(struct ndmp_scsi_session *session, struct ndmp_session_attribute *attr, char *buf);
};
#define to_ndmp_session_attr(x) container_of(x, struct ndmp_session_attribute, attr)

static ssize_t ndmp_session_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
{
	struct ndmp_scsi_session *session;
	struct ndmp_session_attribute *attribute;
	session=to_ndmp_session(kobj);	
	attribute = to_ndmp_session_attr(attr);

	return attribute->show(session, attribute, buf);
}
static ssize_t server_show(struct ndmp_scsi_session *session, struct ndmp_session_attribute *attr, char *buf)
{
	return sprintf(buf,"%s\n",session->ndmp_server);
}

static ssize_t scsi_device_show(struct ndmp_scsi_session *session, struct ndmp_session_attribute *attr, char *buf)
{
	return sprintf(buf,"%s\n",session->scsi_device);
}

static ssize_t device_type_show(struct ndmp_scsi_session *session, struct ndmp_session_attribute *attr, char *buf)
{
                if ( session->device_type == TAPE_DEVICE ) {
                        return sprintf(buf,"TAPE_DEVICE\n");
                } else return sprintf(buf,"ROBOT_DEVICE\n");

}

static ssize_t cmd_seq_number_show(struct ndmp_scsi_session *session, struct ndmp_session_attribute *attr, char *buf)
{
	return sprintf(buf,"%d\n",session->seq_number);
}


static ssize_t session_id_show(struct ndmp_scsi_session *session, struct ndmp_session_attribute *attr, char *buf)
{
	return sprintf(buf,"%d\n",session->session_id);
}

static ssize_t session_state_show(struct ndmp_scsi_session *session, struct ndmp_session_attribute *attr, char *buf)
{

	unsigned long a,b,c,d;
	int t=0;
	
       a=__ndmp_session_state(session,HBA_STATE_CONNECTION);
       b=__ndmp_session_state(session,HBA_STATE_AUTH);
       c=__ndmp_session_state(session,HBA_STATE_DEVICE);
       d=__ndmp_session_state(session,HBA_STATE_THREAD);

       if ( a == _NDMP_STAT_NR ) t+=sprintf(buf+t,"Connection State: Not Ready\n");
       else  if ( a == _NDMP_STAT_IN_PROGRESS ) t+=sprintf(buf+t,"Connection State: In Progress\n");
       else  if ( a == _NDMP_STAT_FAILED ) t+=sprintf(buf+t,"Connection State: Failed\n");
       else  t+=sprintf(buf+t,"Connection State: Established\n");

       if ( b == _NDMP_STAT_NR ) t+=sprintf(buf+t,"Authentication State: Not Ready\n");
       else  if ( b == _NDMP_STAT_IN_PROGRESS ) t+=sprintf(buf+t,"Authentication State: In Progress\n");
       else  if ( b == _NDMP_STAT_FAILED ) t+=sprintf(buf+t,"Authentication State: Failed\n");
       else  t+=sprintf(buf+t,"Authentication State: Done\n");

       if ( c == _NDMP_STAT_NR ) t+=sprintf(buf+t,"Device State: Not Ready\n");
       else  if ( c == _NDMP_STAT_IN_PROGRESS ) t+=sprintf(buf+t,"Device State: In Progress\n");
       else  if ( c == _NDMP_STAT_FAILED ) t+=sprintf(buf+t,"Device State: Failed\n");
       else  t+=sprintf(buf+t,"Device State: Opened\n");

       if ( d == _NDMP_STAT_NR ) t+=sprintf(buf+t,"Thread State: Not Ready\n");
       else  if ( d == _NDMP_STAT_IN_PROGRESS ) t+=sprintf(buf+t,"Thread State: Busy\n");
       else  if ( d == _NDMP_STAT_FAILED ) t+=sprintf(buf+t,"Thread State: Failed\n");
       else  t+=sprintf(buf+t,"Thread State: idle\n");
	
	return t;

}

static ssize_t scsihostname_show(struct ndmp_scsi_session *session, struct ndmp_session_attribute *attr, char *buf)
{
	return sprintf(buf,"scsi%d\n",session->shost->host_no);
}

static struct ndmp_session_attribute ndmp_server_attribute = __ATTR_RO(server);
static struct ndmp_session_attribute ndmp_scsi_device_attribute = __ATTR_RO(scsi_device);
static struct ndmp_session_attribute ndmp_device_type_attribute = __ATTR_RO(device_type);
static struct ndmp_session_attribute ndmp_seq_number_attribute = __ATTR_RO(cmd_seq_number);
static struct ndmp_session_attribute ndmp_session_id_attribute = __ATTR_RO(session_id);
static struct ndmp_session_attribute ndmp_session_state_attribute = __ATTR_RO(session_state);
static struct ndmp_session_attribute ndmp_host_id_attribute = __ATTR_RO(scsihostname);

static struct attribute *ndmp_session_default_attrs[] = {
        &ndmp_server_attribute.attr,
        &ndmp_scsi_device_attribute.attr,
        &ndmp_device_type_attribute.attr,
        &ndmp_seq_number_attribute.attr,
        &ndmp_session_id_attribute.attr,
        &ndmp_session_state_attribute.attr,
        &ndmp_host_id_attribute.attr,
        NULL,   
};

static struct sysfs_ops ndmp_session_sysfs_ops = {
        .show = ndmp_session_attr_show,
        .store = NULL,
};

void ndmp_session_release(struct kobject *kobj)
{
	return;
}

static struct kobj_type ndmp_session_ktype = {
        .sysfs_ops = &ndmp_session_sysfs_ops,
        .release = ndmp_session_release,
        .default_attrs = ndmp_session_default_attrs,
};

int ndmp_create_kset(void)
{
	if ( ! (sessions.ks=kset_create_and_add("ndmphba", NULL, NULL))) return -ENOMEM;
	return 0;
}

void ndmp_destroy_session_kobj(struct ndmp_scsi_session *session)
{
	sysfs_remove_link(&session->ko, "scsihost");
        if (session->ko.name) kobject_put(&session->ko);
}

int ndmp_create_session_kobj(struct ndmp_scsi_session *session)
{
	session->ko.kset = sessions.ks;
	if (kobject_init_and_add(&session->ko, &ndmp_session_ktype, NULL, "%d", session->session_id)) return -1;
	kobject_uevent(&session->ko, KOBJ_ADD);
	if ( sysfs_create_link(&session->ko,&session->shost->shost_gendev.kobj,"scsihost") ) {
		printk("ndmphba: Unable to create sysfs link for the scsihost\n");
	}
	return 0;

}

void ndmp_scsi_kset_remove(void)
{
	kset_unregister(sessions.ks);
}
#endif
